package cn.com.utils;


import cn.hutool.core.util.ObjectUtil;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 线程本地工具类，用于在线程间传递数据或保存线程私有的数据。
 * 使用 InheritableThreadLocal，确保子线程能够继承父线程中的数据。
 * 注意：此类不适用于在异步场景中传递数据，如使用 CompletableFuture 等异步操作。
 *
 * @author LiuGuodong
 * @date 2024/01/11
 */
public class ThreadLocalUtil {

    /**
     * 线程本地变量，存储线程私有的数据。
     */
    private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL = new InheritableThreadLocal<>();

    /**
     * 私有构造方法，防止实例化。
     */
    private ThreadLocalUtil() {
    }

    /**
     * 向线程本地存储中设置数据。
     *
     * @param key   键
     * @param value 值
     */
    public static synchronized void set(String key, Object value) {
        if (key == null || value == null) {
            return;
        }
        Map<String, Object> map = THREAD_LOCAL.get();
        if (map == null) {
            map = new ConcurrentHashMap<>();
            THREAD_LOCAL.set(map);
        }
        map.put(key, value);
    }

    /**
     * 从线程本地存储中获取数据。
     *
     * @param key 键
     * @return 对应键的值，如果不存在则返回 null
     */
    public static Object get(String key) {
        if (key == null) {
            return null;
        }
        Map<String, Object> map = THREAD_LOCAL.get();
        if (map == null) {
            return null;
        }
        return map.get(key);
    }


    /**
     * 缓存
     *
     * @param key        关键
     * @param func       func
     * @param parameters 参数
     * @return {@link R}
     */
    public static <T, R> R cache(String key, Function<T, R> func, T parameters) {
        Object value = ThreadLocalUtil.get(key);
        if (ObjectUtil.isNotEmpty(value)) {
            return (R) value;
        }
        value = func.apply(parameters);
        ThreadLocalUtil.set(key, value);
        return (R) value;
    }

    /**
     * 缓存
     *
     * @param key  key
     * @param func func
     * @return {@link R}
     */
    public static <R> R cache(String key, Supplier<R> func) {
        Object value = ThreadLocalUtil.get(key);
        if (ObjectUtil.isNotEmpty(value)) {
            return (R) value;
        }
        value = func.get();
        ThreadLocalUtil.set(key, value);
        return (R) value;
    }


    /**
     * 判断线程本地存储中是否包含指定键。
     *
     * @param key 键
     * @return 如果包含指定键则返回 true，否则返回 false
     */
    public static synchronized boolean contains(String key) {
        if (key == null) {
            return false;
        }
        Map<String, Object> map = THREAD_LOCAL.get();
        if (map == null) {
            return false;
        }
        return ObjectUtil.isNotEmpty(map.get(key));
    }

    /**
     * 从线程本地存储中移除指定键的数据。
     *
     * @param key 键
     */
    public static synchronized void remove(String key) {
        if (key == null) {
            return;
        }
        Map<String, Object> map = THREAD_LOCAL.get();
        if (map == null) {
            return;
        }
        map.remove(key);
    }

    /**
     * 清空线程本地存储中的所有数据。
     */
    public static synchronized void clear() {
        THREAD_LOCAL.remove();
    }


}
